/*********************************************************
 *	Description:	The implementation of SurF protocol.
 *	Project:		SurF
 *	Author:		Zheng Xiaolong
 *	Updated:		2012/10/23
 *********************************************************/
 
#include <Timer.h>
#include "SurF.h"
#include "SurFC.h"
#include "printf.h"
#include "logValue.h"

module SurFC {

  uses interface CC2420Packet;
  uses interface Boot;
  uses interface Leds;
  
  uses {
  	interface Timer<TMilli> as Timer0;
  	interface Timer<TMilli> as Delay;
  	interface Timer<TMilli> as StartTimer;
  	interface Timer<TMilli> as DATATimer;
  	interface Timer<TMilli> as REQTimer;
  	interface Timer<TMilli> as ADVTimer;
  }
  
  uses interface Packet;
  uses interface AMPacket;
  uses interface AMSend;
  uses interface Receive;
  uses interface SplitControl as AMControl;

  uses interface Bcast;
  uses interface GlobalTime<TMilli>;
  uses interface TimeSyncInfo;
  uses interface PacketTimeStamp<TMilli,uint32_t>;
  uses interface Random;
  

  uses interface CollectionDebug;  
  uses interface SplitControl as SerialControl;
  uses interface Receive as SerialReceive;
  uses interface AMSend as UARTSend;

  uses interface Queue<message_t*>;
  uses interface Pool<message_t>;

  uses {
  	interface AMSend as SendAdvMsg;
   	interface Receive as ReceiveAdvMsg;
    	interface Receive as ReceiveDataMsg;
    	interface Receive as ReceiveReqMsg;
    	interface AMSend as SendDataMsg;
    	interface AMSend as SendReqMsg;
  }

#ifdef ENABLE_EXTLOG
  uses interface SplitControl as LogControl;
  uses interface Timer<TMilli> as DelayTimer;
#endif

}


implementation {
  enum {
  	ROOT_ID = 0,
  };
  
  uint16_t pktNo = 0;
  message_t pkt;
  bool busy = FALSE;
  bool sync = FALSE;

  uint16_t broadcastCounter = 0;
  uint16_t receiveCounter = MAX_PACKET;
  uint8_t receiveRnd = 0;
  uint16_t nowTxPacket = MAX_PACKET;
  uint8_t forward  = 0;
  uint8_t pktsToSend[BITMAP_BYTE];
  uint8_t pktsToRcv[BITMAP_BYTE];
  uint8_t bitmap[BITMAP_BYTE];
  uint8_t bitmap_seg = 0;
  uint8_t bitmap_offset = 0;
  uint8_t repeat = 0;
  uint16_t lastRcv = MAX_PACKET;
  uint8_t round = 0;
  uint32_t rxTimestamp =0;
  uint32_t local = 0;
  uint8_t is_synced = 0;
  uint32_t global_rx_timestamp = 0;
  uint8_t firstPacket = 2;
  uint8_t lastPacket = 0;
  uint32_t firstPktTime = 0;
  uint32_t lastPktTime = 0;
  uint8_t suppressionCounter = 0;
  uint16_t lstHeard = MAX_PACKET;
  uint16_t rcvNum = 0;
  uint16_t sndNum = 0;

  // the neighbor id to whom the req is sent.
  uint16_t reqNbr = 500;
  uint8_t REQCounter = 0;
  uint8_t ADVCounter = 0;
  uint8_t floodingtime = 0;
  //uint8_t maxflood = 0;
  uint8_t specialADVflag = 0;
  uint8_t nodeState = 0xDD;
  uint8_t bcastProb = BCASTPPROBABILITY;
  uint16_t seqno =0 ;

  int workingPage = -1;
  int nextPage = 0;
  int hasPage = -1;
  int sentPage = -1;

  uint8_t requestNum=0; 
  uint16_t ran = 0;
  uint16_t temp =0;
  uint32_t testPara = 0;
  uint32_t  nowtime = 0;
  
   // uint8_t rebroadcast_N = 0;
  uint8_t sendingQ[PACKET_NUMBER];
  struct neighbor upperNeighTable[MAX_NEIGHBOR];
  struct neighbor downNeighTable[MAX_NEIGHBOR];
  uint8_t downNeighSize = 0;
  uint8_t upperNeighSize = 0;

  settings_t settings;

  void sendAdv();
  void sendData();
  void sendReq();
  
  void setLeds(uint16_t val) {
    if (val & 0x01)
      call Leds.led0On();
    else 
      call Leds.led0Off();
    if (val & 0x02)
      call Leds.led1On();
    else
      call Leds.led1Off();
    if (val & 0x04)
      call Leds.led2On();
    else
      call Leds.led2Off();
  }

 uint8_t lookNeighbor(struct neighbor table[MAX_NEIGHBOR], uint16_t target) {
 	int i = 0;
 	for(i=0;i<MAX_NEIGHBOR;i++){
 		if(table[i].nodeid == target) {
			return i;
 		}
 	}
 	return 255;
 }
  
  uint8_t needForward()  {
  	//Flag "need" represents the decision of forwarding the received packet.
  	//need=0, no need to broadcast; 
  	//need=1, need to broadcast; 
  	//need=2, broadcast counter stay unchanged.
  	uint8_t need = 0;
  	int threshold = 0;
  	bitmap_seg = receiveCounter / 8;
  	bitmap_offset = receiveCounter % 8;
	ran = call Random.rand16();	
	//printf("ran: %u\n", ran);
	//temp = ran*10/65536UL;
	threshold = bcastProb*65535/100UL;

	if(! BITVEC_GET(bitmap,receiveCounter)) {
		need =1;
		return need;
	}
  	
#ifdef COUNTER_BASED
	// this is for coutner-based method.
  	else if(suppressionCounter >= SUPP_COUNTER_4) {
  		//suppression is not performed in Deluge Data transmission.
  		need = 0;
  	}
	else if(suppressionCounter < SUPP_COUNTER_4)	{
		need = 2;
	}
	if(TOS_NODE_ID==ROOT_ID) {
		need = 2;
	}
#endif

#ifdef PROBABILITY_BASED
	// this is for probabilistic scheme
  	else if(ran <= threshold) { 	
  		need = 2;
  	}
	else if(ran >= threshold) {
		need = 0;
	}
	if(TOS_NODE_ID==ROOT_ID) {
		need = 2;
	}
#endif

  	return need;
  }

  void setBcastCounter()  {
  //broadcastCounter = BCASTCOUNTER;
  //printf("c:%u\n",broadcastCounter);
  
  	int linkQ = 0;
  	int tempdata = 0;
  	int negh = 0;
  	//to decide which neighbor is used.
  	negh = (int)((call Random.rand16())*downNeighSize/65535L);
  	linkQ = downNeighTable[negh].prr;
  	tempdata = 100 - (int) (bcastProb*linkQ/100);

  	// if no downstream neighbors are founded, then use default bcastcounter.
  	if(downNeighSize==0) {
  		broadcastCounter = BCASTCOUNTER;
  	}
  	// if has downstream neighbor, use equation in paper to calc the bcastcounter.
  	else{
  		broadcastCounter = (int) (logValue[(int)(-linkQ/logValue[tempdata])]/logValue[tempdata])+1;
  	}  
  }

  event void Boot.booted() {
    call SerialControl.start();
  }

  event void SerialControl.startDone(error_t err) {
    if (err == SUCCESS) {
      call LogControl.start();
    }
    else {
    	call SerialControl.start();
    }
  }
  
  event void SerialControl.stopDone(error_t err) { }
  
  event void LogControl.startDone(error_t err) {
  	if (err == SUCCESS) {
		call CollectionDebug.logEventFL(0xAA, 0xBB, 0xCCCC, 0xDDDDDDDD, 0xEEEEEEEE, 0xAAAA, 0xBBBB);
  		call AMControl.start();
    	}
    	 else {
    		call LogControl.start();
   	 }
  }
  
  event void LogControl.stopDone(error_t err) { }
  
  event void AMControl.startDone(error_t err) {
	uint8_t j = 0;
	//uint32_t tempTime = 0;

  	for(; j < BITMAP_BYTE;j++) {
  	 	bitmap[j] = 0x00;
  		pktsToRcv[j] = 0xFF;
	}

    	if (err == SUCCESS) {
    		if(TOS_NODE_ID==ROOT_ID) {
			//setBcastCounter();
			call Bcast.startSync();
        	}

      		call StartTimer.startOneShot(20000);
    	}
    	else {
      		call AMControl.start();
    	}
  }

  event void AMControl.stopDone(error_t err) { }


  event void Delay.fired() {
	//uint8_t j = 0;
  	if(nodeState!=STATE_IDLE) {
  		return;
  	}
  	if(TOS_NODE_ID==ROOT_ID && workingPage<MAX_PAGE){
  		workingPage++;
  	}
  	else if (workingPage>MAX_PAGE){
  		return;
  	}
  	setBcastCounter();
  	specialADVflag = 0;
  	pktNo = 0;
  	ADVCounter=0;
  	nodeState = STATE_FLOD;
  	firstPktTime = 0;
  	firstPacket = 2;
  	lastPktTime = 0;
  	call ADVTimer.stop();
  	call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
  }
  
  event void StartTimer.fired() {
  	//call Leds.led2On();
  	nowtime = call Bcast.getTime();
	call CollectionDebug.logEventFL(LOG_START, 0x00, TOS_NODE_ID, nowtime, 0x00, 0x00, 0x00);
	
	if(TOS_NODE_ID==ROOT_ID) {
		setBcastCounter();
		nodeState = STATE_FLOD;
		workingPage = 0;
		hasPage = MAX_PAGE;
	  	call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
  	}
  	else {
  		nodeState = STATE_IDLE;
  	}
  }

  event void Timer0.fired() {
	uint32_t tempTime = 0;

	if(nodeState!=STATE_FLOD) {
		return;
	}
	
	if(pktNo==0) { 
		firstPktTime = call Bcast.getTime();
	}
	if(pktNo>=PACKET_NUMBER) {
		call Timer0.stop();
		if(lastPktTime == 0){ 
			lastPktTime = call Bcast.getTime();
			call CollectionDebug.logEventFL(LOG_FLOODING,workingPage,TOS_NODE_ID,firstPktTime,lastPktTime,sndNum,rcvNum);
			nodeState = STATE_NEGO;
			setLeds(0);
			call Leds.led2On();
			sendAdv();
		}
		return;
	}
	
  	//checking itself need broadcast or not and sending which one
  	if(broadcastCounter<=0) {
  		setBcastCounter();
  		pktNo++;
  	}
  	if(broadcastCounter>10) {
  		broadcastCounter=BCASTCOUNTER;
  	}

#ifdef PROBABILITY_BASED
	//this is for probabilistic method.	
	if(needForward() == 0)
	{
		broadcastCounter -= 1;
		return;
	}
	//call Leds.led1On();
#endif

  	broadcastCounter -= 1;
  	sndNum++;

    	//pktNo++;
    	if (!busy) {
      		SurFFloodingMsg* btrpkt = (SurFFloodingMsg*)(call Packet.getPayload(&pkt, sizeof(SurFFloodingMsg)));
      		if (btrpkt == NULL) {
			return;
      		}
      		btrpkt->seqno = seqno;
      		btrpkt->nodeid = TOS_NODE_ID;
      		tempTime = call Bcast.getTime();
  
      		btrpkt->counter = pktNo;
      		btrpkt->rnd = workingPage;
      		call CollectionDebug.logEventFL(LOG_SEND, workingPage, TOS_NODE_ID, tempTime, pktNo, 0xAAAA, 0xBBBB);
      		nowTxPacket = btrpkt->counter;

		if (btrpkt->counter>=PACKET_NUMBER) {
			return;
		}
		
      		if (call AMSend.send(AM_BROADCAST_ADDR, &pkt, sizeof(SurFFloodingMsg)) == SUCCESS) {
       		 busy = TRUE;
      		}
      
    	}
  }

  event void AMSend.sendDone(message_t* msg, error_t err) {

    	SurFFloodingMsg* btrpkt = (SurFFloodingMsg*)(call Packet.getPayload(&pkt, sizeof(SurFFloodingMsg)));
  
    	if (btrpkt == NULL) {    
		return;
    	}
    	seqno++;
    	busy = FALSE;
  }

  event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len){
  	uint8_t shortPrr = 0;
  	int position = -1;
    	if (len == sizeof(SurFFloodingMsg)) {
    
      	SurFFloodingMsg* rcm = (SurFFloodingMsg*)payload;
      	receiveCounter = rcm->counter;
      	receiveRnd = rcm->rnd;
      	if(rcm->rnd>=workingPage){
	      	position = lookNeighbor(upperNeighTable,rcm->nodeid);
	      	if(position == 255 && upperNeighSize<10) {
	      		upperNeighTable[upperNeighSize].nodeid = rcm->nodeid;
	      		upperNeighTable[upperNeighSize].prr = 1;
	      		upperNeighTable[upperNeighSize].lastSeqno = rcm->seqno;
	      		upperNeighSize++;
	      	}
	      	else if (position!=-1){
	      		shortPrr = 100/(rcm->seqno - upperNeighTable[position].lastSeqno);
	      		upperNeighTable[position].prr = (uint8_t) (0.2*upperNeighTable[position].prr + 0.8*shortPrr);
	      		upperNeighTable[upperNeighSize].lastSeqno = rcm->seqno;	
	      	}
      	}
      	else {
	      	position = lookNeighbor(downNeighTable,rcm->nodeid);
	      	if(position == 255 && downNeighSize<10) {
	      		downNeighTable[downNeighSize].nodeid = rcm->nodeid;
	      		downNeighTable[downNeighSize].prr = 1;
	      		downNeighTable[downNeighSize].lastSeqno = rcm->seqno;
	      		downNeighSize++;
	      	}
	      	else if (position!=-1){
	      		shortPrr = 100/(rcm->seqno - downNeighTable[position].lastSeqno);
	      		downNeighTable[position].prr = (uint8_t)(0.2*downNeighTable[position].prr + 0.8*shortPrr);
	      		downNeighTable[position].lastSeqno = rcm->seqno;
	      	}
      	}

	if(rcm->rnd>MAX_PAGE){
		return msg;	
	}

      	reqNbr = rcm->nodeid;
    	if(call PacketTimeStamp.isValid(msg)) {
    		call Leds.led0Toggle();
    		rcvNum++;
    	}
    
	if(TOS_NODE_ID==ROOT_ID) {
		return msg;
	}
    
    	if(nodeState==STATE_IDLE && rcm->rnd<=hasPage) {
    		return msg;
    	}
    	if(nodeState==STATE_RX&&rcm->rnd!=workingPage){
    		return msg;
    	}

    	if(nodeState!=STATE_RX&& rcm->rnd>hasPage&& rcm->rnd==nextPage) {
    		nodeState = STATE_RX;
    		specialADVflag = 0;
    		workingPage = rcm->rnd;
    		call ADVTimer.stop();
    	}
    
	if(rcm->rnd<workingPage) {
		return msg;
	}
    
    	if(firstPacket==2) {
    		firstPacket = 1;
    	}

	rxTimestamp = call PacketTimeStamp.timestamp(msg);
	local = call Bcast.getTime();
	if(firstPacket==1) {
		firstPktTime =  local;
		firstPacket = 0;
	}
	
	if(lstHeard == receiveCounter) {
		suppressionCounter++;
	}
	else {
		suppressionCounter = 0;
	}

	lstHeard = receiveCounter;
	
      	if(! BITVEC_GET(bitmap,receiveCounter)) {
		call CollectionDebug.logEventFL(LOG_RECE, receiveRnd, TOS_NODE_ID, local, receiveCounter, 0xAAAA, 0xBBBB);
      	}

  	BITVEC_SET(bitmap,receiveCounter);
  	BITVEC_CLEAR(pktsToRcv,receiveCounter);
    }
    return msg;
}


  void sendData()  {

	SurFDataMsg *pDataMsg = (SurFDataMsg *)(call SendDataMsg.getPayload(&pkt, sizeof(SurFDataMsg)));
  	uint8_t i = 0;
  	uint8_t pktNumToSend = 222;
  	
	for(i=0;i<PACKET_NUMBER;i++)	{
		if(BITVEC_GET(pktsToSend,i)) {
			if(pktNumToSend==222) {
				pktNumToSend = i;
			}
		}
	}
	
	// All requested packets have been sent out.
	if(pktNumToSend==222) {
		nodeState = STATE_IDLE;
		call DATATimer.stop();
		if(TOS_NODE_ID==ROOT_ID){
			call Delay.stop();
			call Delay.startOneShot(500);
		}
		setLeds(0);
		call ADVTimer.startPeriodic(ADV_TIMEOUT);  
		return;
	}

	pDataMsg->seqno = seqno;
	pDataMsg->nodeid = TOS_NODE_ID;
	pDataMsg->pgNum = workingPage;
	pDataMsg->pktNum = pktNumToSend;
	if(pDataMsg->pgNum>MAX_PAGE) {
		workingPage = 0;
		hasPage = 0;
		return;
	}
    	call DATATimer.startOneShot(5);
   	 if(!busy){
	   	if (call SendDataMsg.send(AM_BROADCAST_ADDR, &pkt, sizeof(SurFDataMsg)) == SUCCESS) {
	    		busy = TRUE;	
	    	}
    	}
  }


  event void SendDataMsg.sendDone(message_t* msg, error_t error) {
  	uint32_t tempTime = 0;
    	SurFDataMsg *pDataMsg = (SurFDataMsg *)(call SendDataMsg.getPayload(&pkt, sizeof (SurFDataMsg)));
	if(pDataMsg==NULL){
		return;
	}

	seqno++;
	tempTime = call Bcast.getTime();
    	busy = FALSE;
    	call CollectionDebug.logEventFL(AM_SURFDATAMSG,LOG_SEND,TOS_NODE_ID,tempTime, pDataMsg->pktNum,pDataMsg->pgNum,0xBBBB);
    	BITVEC_CLEAR(pktsToSend, pDataMsg->pktNum);
  }

  event void DATATimer.fired(){
  	sendData();
  }

  void sendReq() {
    	uint8_t i;
	SurFReqMsg *pReqMsg = (SurFReqMsg *)(call SendReqMsg.getPayload(&pkt, sizeof (SurFReqMsg)));

    	if (pReqMsg == NULL) {
      		return;
    	}
    	if(nodeState!=STATE_RX){
    		return;
    	}
    	pReqMsg->seqno = seqno;
    	pReqMsg->dest = reqNbr;
    	pReqMsg->sourceAddr = TOS_NODE_ID;
    	pReqMsg->rnd = 0;
    	pReqMsg->pgNum = workingPage;
    	for (i = 0; i < BITMAP_BYTE; i++) {
   		pReqMsg->requestedPkts[i] = pktsToRcv[i];
    	}
	if(pReqMsg->pgNum>MAX_PAGE){
		workingPage = 0;
		hasPage = 0;
		return;
	}
    	if(!busy){
	    	if (call SendReqMsg.send(pReqMsg->dest, &pkt, sizeof(SurFReqMsg)) == SUCCESS) {	    	
	    		busy = TRUE;
	    	}
	}
  }

  event void SendReqMsg.sendDone(message_t* msg, error_t error) {
  	SurFReqMsg *pReqMsg = (SurFReqMsg *)(call SendReqMsg.getPayload(&pkt, sizeof (SurFReqMsg)));
    	uint32_t tempTime = 0;
	tempTime = call Bcast.getTime();
  	if(&pkt!=msg) {
  		return;
  	}
	seqno++;
  	busy = FALSE;
  	REQCounter++;
	call CollectionDebug.logEventFL(AM_SURFREQMSG,LOG_SEND,0x00,tempTime, pReqMsg->pgNum,TOS_NODE_ID,pReqMsg->dest);
  	call REQTimer.startOneShot(REQ_TIMEOUT);
  }

  event void REQTimer.fired(){
	//if(data has come) no more send
  	//else if there is no data, time out, sendReq();
  	if(REQCounter<MAX_REQ) {
  		sendReq();
  	}
  }

  void sendAdv() {
  	SurFAdvMsg *pAdvMsg = (SurFAdvMsg *)(call SendAdvMsg.getPayload(&pkt, sizeof(SurFAdvMsg)));
	if(pAdvMsg==NULL){
		return;
	}
	call Leds.led1Toggle();
	ADVCounter++;
	if(ADVCounter<3) {
		call ADVTimer.startOneShot(15);
	}
	if(ADVCounter==3){
		call ADVTimer.startPeriodic(ADV_TIMEOUT);  
	}
	//if two periodical ADV and three special ADV get no response, 
	//root will beleive children have all received this page, starting next page.
	if(ADVCounter>4 && TOS_NODE_ID==ROOT_ID && workingPage<MAX_PAGE){
		call Delay.stop();
		call Delay.startOneShot(50);
	}
	pAdvMsg->seqno = seqno;
	pAdvMsg->sourceAddr = TOS_NODE_ID;
	pAdvMsg->version = workingPage;
	if(ADVCounter<3) {
		pAdvMsg->type = 1;
	}
	else {
		pAdvMsg->type = 0;
	}
	
    	if(!busy){
	    	if (call SendAdvMsg.send(AM_BROADCAST_ADDR, &pkt, sizeof(SurFReqMsg)) == SUCCESS) {
	    		busy = TRUE;
	    	}
	}
  }

  event void SendAdvMsg.sendDone(message_t* msg, error_t error) {

    	SurFAdvMsg *pAdvMsg = (SurFAdvMsg *)(call SendAdvMsg.getPayload(&pkt, sizeof(SurFAdvMsg)));
    	uint32_t tempTime = 0;
	tempTime = call Bcast.getTime();

	busy = FALSE;

  	if(&pkt!=msg) {
  		return;
  	}
  	seqno++;
	call CollectionDebug.logEventFL(AM_SURFADVMSG,LOG_SEND,0x00,tempTime, pAdvMsg->version,TOS_NODE_ID,0x00);

  	
  }

  event void ADVTimer.fired(){
  	sendAdv();
  }
  
  event message_t* ReceiveReqMsg.receive(message_t* msg, void* payload, uint8_t len){
    	int i;
    	int position = -1;
    	uint8_t shortPrr = 0;
	SurFReqMsg *rxReqMsg = (SurFReqMsg*)payload;
  	uint32_t tempTime = 0;
	tempTime = call Bcast.getTime();

	call Leds.led2On();

	if(nodeState==STATE_RX){
		return msg;
	}

	if(rxReqMsg->dest==TOS_NODE_ID) {
	      	position = lookNeighbor(downNeighTable,rxReqMsg->sourceAddr);
	      	if(position == 255 && downNeighSize<10) {
	      		downNeighTable[downNeighSize].nodeid = rxReqMsg->sourceAddr;
	      		downNeighTable[downNeighSize].prr = 1;
	      		downNeighTable[downNeighSize].lastSeqno = rxReqMsg->seqno;
	      		downNeighSize++;
	      	}
	      	else if (position!=-1){
	      		shortPrr = 100/(rxReqMsg->seqno - downNeighTable[position].lastSeqno);
	      		downNeighTable[position].prr = 0.2*downNeighTable[position].prr + 0.8*shortPrr;
	      		downNeighTable[position].lastSeqno = rxReqMsg->seqno;
	      	}
	}
    	if(rxReqMsg->pgNum>hasPage){
    		return msg;
    	}
	if(rxReqMsg->pgNum<workingPage){
		workingPage = rxReqMsg->pgNum;
	}
	call CollectionDebug.logEventFL(AM_SURFREQMSG,LOG_RECE,0x00,tempTime, rxReqMsg->pgNum,TOS_NODE_ID,rxReqMsg->sourceAddr);
    	for (i = 0; i < BITMAP_BYTE; i++) {
        	pktsToSend[i] |= rxReqMsg->requestedPkts[i];
    	}
	call ADVTimer.stop();
	sendData();
	return msg;
  }

  event message_t* ReceiveDataMsg.receive(message_t* msg, void* payload, uint8_t len) {
  	uint8_t i = 0;
  	uint8_t reqSendFlag = 0;
  	uint32_t tempTime = 0;
  	uint8_t shortPrr = 0;
  	int position  = -1;
	SurFDataMsg* rxDataMsg = (SurFDataMsg*)payload;
	tempTime = call Bcast.getTime();

	if(rxDataMsg->pgNum>MAX_PAGE){
		return msg;
	}
	if(rxDataMsg->pgNum>=workingPage){
	      	position = lookNeighbor(upperNeighTable,rxDataMsg->nodeid);
	      	if(position == 255 && upperNeighSize<10) {
	      		upperNeighTable[upperNeighSize].nodeid = rxDataMsg->nodeid;
	      		upperNeighTable[upperNeighSize].prr = 1;
	      		upperNeighTable[upperNeighSize].lastSeqno = rxDataMsg->seqno;
	      		upperNeighSize++;
	      	}
	      	else if (position!=-1){
	      		shortPrr = 100/(rxDataMsg->seqno - upperNeighTable[position].lastSeqno);
	      		upperNeighTable[position].prr = 0.2*upperNeighTable[position].prr + 0.8*shortPrr;
	      		upperNeighTable[upperNeighSize].lastSeqno = rxDataMsg->seqno;	
	      	}
      	}
      	else {
	      	position = lookNeighbor(downNeighTable,rxDataMsg->nodeid);
	      	if(position == 255 && downNeighSize<10) {
	      		downNeighTable[downNeighSize].nodeid = rxDataMsg->nodeid;
	      		downNeighTable[downNeighSize].prr = 1;
	      		downNeighTable[downNeighSize].lastSeqno = rxDataMsg->seqno;
	      		downNeighSize++;
	      	}
	      	else if (position!=-1){
	      		shortPrr = 100/(rxDataMsg->seqno - downNeighTable[position].lastSeqno);
	      		downNeighTable[position].prr = 0.2*downNeighTable[position].prr + 0.8*shortPrr;
	      		downNeighTable[position].lastSeqno = rxDataMsg->seqno;
	      	}
      	}
	if(rxDataMsg->pgNum!=workingPage){
		return msg;
	}
	if(nodeState!=STATE_RX){
		return msg;
	}
	call REQTimer.stop();
	call Leds.led0Off();
	  
      	BITVEC_SET(bitmap,rxDataMsg->pktNum);
      	BITVEC_CLEAR(pktsToRcv,rxDataMsg->pktNum);
      	call CollectionDebug.logEventFL(AM_SURFDATAMSG,LOG_RECE,TOS_NODE_ID,tempTime, rxDataMsg->pktNum,rxDataMsg->pgNum,0xBBBB);
      	for(i=0;i<BITMAP_BYTE;i++) {
	  	if(bitmap[i]!=0xFF) {
			reqSendFlag = 1;
	  	}
	}
	if(reqSendFlag==0 && nodeState==STATE_RX){
		nodeState = STATE_IDLE;
	  	if(TOS_NODE_ID!=ROOT_ID){
			hasPage = workingPage;
			nextPage = hasPage+1;
		}
	   	for(i=0; i <BITMAP_BYTE;i++) {
  	    		call CollectionDebug.logEventFL(LOG_BITMAP, LOG_NEGOTIATION, 0x0000, 0x00000000, 0x00000000, i, bitmap[i]);
  	   		bitmap[i] = 0x00;
	  		pktsToRcv[i] = 0xFF;
  	  	}
  	    	call CollectionDebug.logEventFL(LOG_END, LOG_NEGOTIATION, TOS_NODE_ID, tempTime, workingPage,0xAAAA,0xBBBB);

	  	setLeds(0);
	  	// start rebroadcasting.
		call Delay.stop();
	  	call Delay.startOneShot(200);

	  	return msg;
	}
	else {
	  	call REQTimer.startOneShot(50);
      }
      return msg;
  }
  
  event message_t* ReceiveAdvMsg.receive(message_t* msg, void* payload, uint8_t len) {
	uint8_t i = 0;
	uint8_t reqSendFlag = 0;
  	uint32_t tempTime = 0;
  	int position  = -1;

      	SurFAdvMsg *rxAdvMsg = (SurFAdvMsg*)payload;
	REQCounter = 0;

	position = lookNeighbor(downNeighTable,rxAdvMsg->sourceAddr);
	if(position!=-1) {
		downNeighTable[position].lastSeqno = rxAdvMsg->seqno;
	}
	position = -1;
	position = lookNeighbor(upperNeighTable,rxAdvMsg->sourceAddr);
	if(position!=-1) {
		upperNeighTable[position].lastSeqno = rxAdvMsg->seqno;
	}
//printf("rxP:%u, workP:%u, state:%u,special:%u\n",rxAdvMsg->version,workingPage,nodeState,specialADVflag);
	if(rxAdvMsg->version < workingPage) {
		return msg;
	}
	if(nodeState!=STATE_RX){
		return msg;
	}
	//if(rxAdvMsg->type==0x01 && specialADVflag!=0){
	if(specialADVflag!=0){
	  	return msg;
	}

	//for now, it selects the neighbor whose ADV comes first as its requesting destination.
	reqNbr = rxAdvMsg->sourceAddr;	  
	tempTime = call Bcast.getTime();
	call CollectionDebug.logEventFL(AM_SURFADVMSG,LOG_RECE,rxAdvMsg->type,tempTime, rxAdvMsg->version,TOS_NODE_ID,rxAdvMsg->sourceAddr);

	//if(rxAdvMsg->type==0x01){
	if(specialADVflag==0) {
		specialADVflag = 1;
		for(; i <BITMAP_BYTE;i++){
	  	 	call CollectionDebug.logEventFL(LOG_BITMAP, LOG_FLOODING, 0x0000, 0x00000000, 0x00000000, i, bitmap[i]);
	  	 }
		call CollectionDebug.logEventFL(LOG_FLOODING,workingPage,TOS_NODE_ID,firstPktTime,tempTime,sndNum,rcvNum);
   	      	call CollectionDebug.logEventFL(LOG_END, LOG_FLOODING, TOS_NODE_ID, tempTime, workingPage,0xAAAA,0xBBBB);
		call CollectionDebug.logEventFL(LOG_START, LOG_NEGOTIATION, TOS_NODE_ID, tempTime, workingPage, 0x00, 0x00);
	 }
	  
	for(i=0;i<BITMAP_BYTE;i++) {
	  	if(bitmap[i]!=0xFF){
			reqSendFlag = 1;
	  	}
	}

	if(reqSendFlag==0 && nodeState==STATE_RX){
		nodeState = STATE_IDLE;
	  	if(TOS_NODE_ID!=ROOT_ID) {
			hasPage = workingPage;
			nextPage = hasPage+1;
		}
	  	for(i=0; i <BITMAP_BYTE;i++) {
	  	  	call CollectionDebug.logEventFL(LOG_BITMAP, LOG_FLOODING, 0x0000, 0x00000000, 0x00000000, i, bitmap[i]);
  	        	call CollectionDebug.logEventFL(LOG_END, LOG_NEGOTIATION, TOS_NODE_ID, tempTime, workingPage,0xAAAA,0xBBBB);

	  	    	bitmap[i] = 0x00;
	  	    	pktsToRcv[i] = 0xFF;
	  	}

		call Delay.startOneShot(200);
	  	setLeds(0);
	  	return msg;
	}
	else if(reqSendFlag==1 && nodeState==STATE_RX)  {
	  	sendReq();
      	}
      return msg;
  }

  event message_t* SerialReceive.receive(message_t* msg, void* payload, uint8_t len) {
  	if (len == sizeof(settings_t)) {
      	memcpy(&settings, payload, sizeof(settings_t));
      	switch (settings.type) {
	#ifdef ENABLE_EXTLOG   
        	case DS_SET_DEBUG: // its local
        	{
          		call DelayTimer.startOneShot(3*1024L);
          		break;
        	}
	#endif
        	default:
          	break;
          }
    	}
    	return msg;
  }

#ifdef ENABLE_EXTLOG
event void DelayTimer.fired() {
    	call CollectionDebug.readEvent();
}
#endif

 task void uartEchoTask() { }

  event void UARTSend.sendDone(message_t *msg, error_t error) {
    	call Pool.put(msg);

    	if (error == SUCCESS) {
      		//sink_forward++;
    	}
    
    	if (!call Queue.empty()) {
     		post uartEchoTask();
    	} 
    	else {
    	}
  }

  default command error_t CollectionDebug.logEventFL(uint8_t type, uint8_t rnd, uint16_t nodeID, uint32_t beginTime, uint32_t finishTime, uint16_t sendNum, uint16_t rcvdNum){
    return SUCCESS;
  }
}
